SBT 构建定义 (Build Definition)

两类 Build Definition风格:

  • 新:多工程 .sbt 构建定义
  • 旧:bare .sbt 构建定义

为了指定构建定义的风格,以便用不同风格的构建定义完成相同的项目,可以在基础目录建立 project/build.properties文件,包含下列内容:

sbt.version=1.0.2

注意这里等号两边没有空格

如果当前操作系统环境中没有包含指定版本(风格)的sbt工具,系统会自动下载安装。

Play 2.6 用的SBT版本是 0.13.15,依旧是旧风格。

1. bare .sbt 风格的构建定义

包含了一个完整的 Setting[_],而不区分project.

2. 多工程 .sbt 风格的构建定义

构建定义内容存储在 build.sbt 文件中,它定义了当前目录的工程(subproject)定义,例如:

lazy val root = (project in file("."))
  .settings(
    name := "Hello",
    scalaVersion := "2.12.3"
  )

每一个工程对应一个不可变的映射表(immutable map)(一些键值对的集合)来描述工程。

一个构建定义是一个Project(英文文档中称为 subproject,以防止歧义),拥有一个类型为 Setting[T] 的列表,Setting[T] 是会影响到 sbt 保存键值对的 map 的一种转换,T 是每一个 value 的类型。

每个键值对利用 build.sbt DSL 语言来进行定义,如下图

其中 key 是 SBT SettingKey[T], TaskKey[T], or InputKey[T] 的一个实例。因此,如果对应的value类型不为T,则编译会报错

build.sbt中也可以包含其它 val , lazy val 和 def 对象。

  • SettingKey : 在加载该项目(subproject)时会被计算,此后保持不变
  • TaskKey : 一个key对应一个称为 task 的value,会被重复计算
  • InputKey : 对应task的输入参数,详细的关于 task 和 input 的有这个文档

上述三类是Key的类型,其定义来源则有两类: built-in keys (定义在 sbt.Keys._) 和 custom keys。

自定义的key可以如下列方式定义在 build.sbt文件中。如下例,定义了一个名为 hello的新TaskKey:

lazy val hello = taskKey[Unit]("An example task")

关于Task

TaskKey[T] 是用来定义 task 的。Tasks 就是像 compile 或者 package 这样的操作。它们可能返回 Unit(Unit 在 Scala 中表示 void),或者可能返回 task 相关的返回值, 例如 package 就是一个类型为 TaskKey[File] 的 task, 它的返回值是其生成的 jar 文件。

对于每个 subproject,都定义了它的一系列基本设定和任务。

  • 基本设定为 SettingKey,类似不可更改的全局常量

  • 而任务则用来执行这个project的不同分支功能(计算任务),任务本身由TaskKey定义,任务的输入则由InputKey来定义

Task中保存了计算的代码,例如:

lazy val hello = taskKey[Unit]("An example task")

lazy val root = (project in file("."))
  .settings(
    hello := { println("Hello!") }
  )

添加依赖库

有两种方式添加第三方的依赖。一种是将 jar 文件 放入 lib/(非托管的依赖)中,另一种是在 build.sbt中添加托管的依赖

后者的示例如下(添加版本为 10.4.1.3 的 Apache Derby 库作为依赖):

val derby = "org.apache.derby" % "derby" % "10.4.1.3"

lazy val commonSettings = Seq(
  organization := "com.example",
  version := "0.1.0",
  scalaVersion := "2.12.3"
)

lazy val root = (project in file("."))
  .settings(
    commonSettings,
    name := "hello",
    libraryDependencies += derby
  )

需要注意的是这里 Key libraryDependencies的两个特殊用法,一个是 +=,一个是 %。

Scope

scope 用于定义Key的作用域(上下文 context)

scope轴:就是指哪个维度来划分不同的作用域,共有三种类型:

  • projects
  • configurations
  • tasks

类似于RGB的原色划分,从不同轴上对作用域进行划分、组合后,就可以成为明确的Key作用域了,

因此,一个完整的sbt作用域实际上是一个三元组,包含:subproject, configuration, task,例如:

scalaOptions in (projA, Compile, console)

1. subproject scope axis

可以在一个 single build中包含若干个subprojects, 用来指定每个subproject中独立的Key设定

也可以将设定指定在 ThisBuild,即整个build共享

2. configuration scop axis

configuration scope 常用于包含项目的依赖关系,包括:its own classpath, sources, generated packages, etc.

常见的configuration包括:

  • Compilewhich defines the main build (src/main/scala).
  • Testwhich defines how to build tests (src/test/scala).
  • Runtimewhich defines the classpath for theruntask.

configuration中也可以包含继承关系,如下图

3. task scop axis

不是非常能理解,特别是关于一个task key 可以用于另一个key的作用域的问题。


在进行scope设置时,每个轴都可以用与该轴类型一致的实例代替,(例如 task 轴可以用一个 task 代替),或者该轴可以被特定的值Global代替。

如果一个 task 轴的值是 Global,那么该 setting 的值将被应用到所有的 task 上。

查看 Scope 中 key

$ sbt
> inspect name
...
[info] Provided by:
[info]  {file:/Users/jiamin/Applications/helloSBT/}root/*:name
...

可以看到,上述这个名为 name 的Key,其scope定义的结构为:

{<build-uri>}<project-id>/config:intask::key
  • {<build-uri>}/<project-id> 标识 project 轴。如果 project 轴有构建全局 scope,将没有 <project-id> 部分。 {file:/Users/jiamin/Applications/helloSBT/}root
  • config 标识 configuration 轴。 * 代表全局
  • intask 标识 task 轴。没有显示出来 也代表全局
  • key 标识 scope 下的 key。

可以这样定义不同轴下的Key值

lazy val root = (project in file("."))
  .settings(
    name := "helloSBT",
    version := "1.0",
    scalaVersion := "2.11.4"
  )

organization := name.value
name in Compile := "hello_in_compile"
name in packageBin := "hello in task"

大概能够理解Key的作用,也能理解不同scope下指定相同Key不同值的作用。 但是具体的设置、查看方法,以及在具体使用过程中,应该如何活用这类机制,还不是很清楚。

results matching ""

    No results matching ""